namespace Guia.Elements
{
    using System;
    using System.Diagnostics.Contracts;
    using System.Reflection;
    using System.Windows.Automation;
    using System.Windows.Controls;
    using Guia.Core;

    /// <summary>
    /// This class represents a custom UserControl.
    /// It enables the start, stop and automation of a particular UserControl
    /// </summary>
    public class CustomControl : RunnableUiElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CustomControl"/> class.
        /// </summary>
        /// <param name="control">The AutomationElement.</param>
        public CustomControl(AutomationElement control)
            : base(control)
        {
        }

        /// <summary>
        /// Starts the CustomControl with the given type of UserControl and parameters.
        /// </summary>
        /// <typeparam name="T">The type of the concrete UserControl.</typeparam>
        /// <param name="constructorParameters">The (optional) parameters for the constructor. These parameters are passed to the UserConrols constructor.</param>
        /// <returns>The started CustomControl</returns>
        public static CustomControl Start<T>(params object[] constructorParameters) where T : UserControl
        {
            Type controlType = typeof(T);
            ConstructorInfo constructorInfo = GetConstructorInfo(controlType, constructorParameters);
            return Start(() => (UserControl)constructorInfo.Invoke(constructorParameters));
        }

        /// <summary>
        /// Starts the CustomControl with the given UserControl-type.
        /// </summary>
        /// <param name="initializeAction">
        /// The initialize action. This action is called after the UserControl was created.
        /// </param>
        /// <param name="constructorParameters">
        /// The (optional) parameters for the constructor. These parameters are passed to the UserConrols constructor.
        /// </param>
        /// <typeparam name="T">
        /// The type of the custom UserControl.
        /// </typeparam>
        /// <returns>
        /// The started CustomControl
        /// </returns>
        /// <exception cref="ArgumentNullException">This exception is thrown if initializeAction is null</exception>
        public static CustomControl Start<T>(Action<T> initializeAction, params object[] constructorParameters) where T : UserControl
        {
            Contract.Requires<ArgumentNullException>(initializeAction != null);
            Type controlType = typeof(T);
            ConstructorInfo constructorInfo = GetConstructorInfo(controlType, constructorParameters);
            return Start(() =>
                             {
                                 T userControl = (T)constructorInfo.Invoke(constructorParameters);
                                 initializeAction.Invoke(userControl);
                                 return userControl;
                             });
        }

        /// <summary>
        /// This method is executed, before the Runnable entity is being stopped.
        /// It can contain functionality which stopps modal-windows.
        /// </summary>
        protected override void CloseOpenElements()
        {
            Window[] windows = this.ParentWindow.GetAll<Window>();
            do
            {
                foreach (Window w in windows)
                {
                    try
                    {
                        w.Close();
                    }
                    catch (OperationNotSupportedException)
                    {
                        // not critical
                    }
                }
            }
            while ((windows = this.ParentWindow.GetAll<Window>()).Length > 0);
        }

        /// <summary>
        /// Starts a new CustomControl with the given UserControl-type.
        /// </summary>
        /// <param name="function">The function returning the desired UserControl</param>
        /// <returns>The started CustomControl</returns>
        private static CustomControl Start(Func<UserControl> function)
        {
            string userControlName = string.Empty;
            CustomControl customControl = RunnableUiElement.Start<CustomControl>(() =>
            {
                Grid hostGrid = new Grid();
                UserControl userControl = function.Invoke();
                userControlName = userControl.Name;
                hostGrid.Children.Add(userControl);
                System.Windows.Window hostWindow = new System.Windows.Window();
                hostWindow.Content = hostGrid;
                hostWindow.Title = "UserControlWindow";
                hostWindow.Name = "UserControlWindow";
                hostWindow.SizeToContent = System.Windows.SizeToContent.WidthAndHeight;
                return hostWindow;
            });

            UiElement uiElement = customControl.Get(userControlName);
            customControl.automationElement = uiElement.AutomationElement;
            return customControl;
        }
    }
}